package com.uxsino.simo.query;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections4.keyvalue.MultiKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.uxsino.commons.utils.config.PropElement;
import com.uxsino.reactorq.model.IndicatorValue;
import com.uxsino.simo.indicator.ListIndicator;
import com.uxsino.simo.utils.ConfigLoadingContext;

public class JoinQueryCombine extends QueryCombine<ListIndicator, List<Map<String, Object>>> {
    private static Logger logger = LoggerFactory.getLogger(JoinQueryCombine.class);

    public JoinQueryCombine(ListIndicator resultIndicator) {
        super(resultIndicator);
    }

    @Override
    public List<Map<String, Object>> apply(QueryContext ctxt, List<IndicatorValue> values) {
        List<Map<String, Object>> r = new ArrayList<>();
        ListIndicator ind = getResultIndicator();
        String[] keyNames = ind.getKeyFieldNames();
        for (IndicatorValue v : values) {
            @SuppressWarnings("unchecked")
            List<Map<String, Object>> l = (List<Map<String, Object>>) v.value;

            if (l == null)
                continue;
            for (Map<String, Object> row : l) {
                MultiKey<String> row_key = getRowKey(row, keyNames);
                Map<String, Object> destRow = getRowByKey(r, keyNames, row_key);
                if (destRow == null) {
                    destRow = new HashMap<String, Object>(row);
                    r.add(destRow);
                    continue;
                }
                for (Map.Entry<String, Object> fld : row.entrySet()) {
                    Object value = fld.getValue();

                    if (value != null || !destRow.containsKey(fld.getKey())) {
                        destRow.put(fld.getKey(), fld.getValue());
                    }
                }
            }
        }
        return r;

    }

    private static MultiKey<String> getRowKey(Map<String, Object> row, String[] keyFieldNames) {
        if (keyFieldNames == null)
            return new MultiKey<String>(new String[0]);

        String[] r = new String[keyFieldNames.length];
        for (int i = 0; i < r.length; i++) {
            Object key = row.get(keyFieldNames[i]);
            if (key == null) {
                logger.error("null in key field of combine indicator");
            }
            r[i] = key == null ? null : key.toString();
        }
        return new MultiKey<>(r);

    }

    private static Map<String, Object> getRowByKey(List<Map<String, Object>> l, String[] keyNames,
        MultiKey<String> keyValue) {
        for (Map<String, Object> row : l) {
            MultiKey<String> v = getRowKey(row, keyNames);
            if (v != null && keyValue.equals(v))
                return row;
        }
        return null;
    }

    @Override
    public void loadProp(PropElement eCombine, ConfigLoadingContext lctxt) {

    }

    @Override
    public boolean isCustom() {
        return false;
    }

}
